/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */

#include "app_config.h"

#if TCFG_LIB_FATFS_SUPPORT

#if TCFG_DRV_SD_CARD_SPI_SUPPORT
#include "drv_sd.h"
#endif

#if TCFG_DRV_SPI_NORFLASH_SUPPORT
#include "drv_spi_norflash.h"
#endif

#include "debug.h"

/* Definitions of physical drive number for each drive */
#define DEV_RAM		0	/* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC		1	/* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB		2	/* Example: Map USB MSD to physical drive 2 */
#define DEV_NOR		3	/* NorFlash */

/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat = STA_NOINIT;
	int result;

	switch (pdrv) {
	case DEV_RAM :
		// result = RAM_disk_status();

		// translate the reslut code here
		log_d("disk_status DEV_RAM\n");
		return stat;

	case DEV_MMC :
		// result = MMC_disk_status();

		// translate the reslut code here
		stat = 0;
		log_d("disk_status DEV_MMC\n");
		return stat;

	case DEV_USB :
		// result = USB_disk_status();

		// translate the reslut code here
		log_d("disk_status DEV_USB\n");
		return stat;

	case DEV_NOR:
	#if TCFG_DRV_SPI_NORFLASH_SUPPORT
		log_d("disk_status DEV_NOR\n");		
		stat = 0;
	#endif
		return stat;
	}

	
	return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
	int result;

	switch (pdrv) {
	case DEV_RAM :
		// result = RAM_disk_initialize();

		// translate the reslut code here
		log_d("disk_initialize DEV_RAM\n");
		return stat;

	case DEV_MMC :
		// result = MMC_disk_initialize();

		// translate the reslut code here
	#if TCFG_DRV_SD_CARD_SPI_SUPPORT
		if(SD_Init() == 0) {
			stat = 0;
		} else {
			stat = RES_ERROR;
		}
	#endif
		log_d("disk_initialize DEV_MMC\n");
		return stat;

	case DEV_USB :
		// result = USB_disk_initialize();

		// translate the reslut code here
		log_d("disk_initialize DEV_USB\n");
		return stat;
	case DEV_NOR:
		#if TCFG_DRV_SPI_NORFLASH_SUPPORT
		log_d("disk_initialize DEV_NOR\n");
		NorFlash_Init();
		stat = 0;
		#endif
		return stat;
	}
	return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
	DRESULT res;
	int result;

	switch (pdrv) {
	case DEV_RAM :
		// translate the arguments here

		// result = RAM_disk_read(buff, sector, count);

		// translate the reslut code here
		log_d("disk_read DEV_RAM\n");
		return res;

	case DEV_MMC :
		// translate the arguments here

		// result = MMC_disk_read(buff, sector, count);

		// translate the reslut code here
	#if TCFG_DRV_SD_CARD_SPI_SUPPORT
		if (count == 1) {
			if (SD_ReadSingelBlock(buff, sector) == 0) {
				res = RES_OK;
			} else {
				res = RES_ERROR;
			}
		} else {
			if (SD_ReadMultipleBlock(buff, sector, count) == 0) {
				res = RES_OK;
			} else {
				res = RES_ERROR;
			}
		}
	#endif
		log_d("disk_read DEV_MMC\n");
		return res;

	case DEV_USB :
		// translate the arguments here

		// result = USB_disk_read(buff, sector, count);

		// translate the reslut code here
		log_d("disk_read DEV_USB\n");
		return res;
	case DEV_NOR:
		#if TCFG_DRV_SPI_NORFLASH_SUPPORT
		log_d("disk_read DEV_NOR\n");
		NorFlash_ReadBuffer(buff, sector*NORFLASH_FATFS_SECTOR_SIZE,  count*NORFLASH_FATFS_SECTOR_SIZE);
		res = RES_OK;
		#endif
		return res;
	}

	return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
	DRESULT res;
	int result;

	switch (pdrv) {
	case DEV_RAM :
		// translate the arguments here

		// result = RAM_disk_write(buff, sector, count);

		// translate the reslut code here
		log_d("disk_write DEV_RAM\n");
		return res;

	case DEV_MMC :
		// translate the arguments here

		// result = MMC_disk_write(buff, sector, count);

		// translate the reslut code here
	#if TCFG_DRV_SD_CARD_SPI_SUPPORT
		if (count == 1) {
			if (SD_WriteSingleBlock(buff, sector) == 0) {
				res = RES_OK;
			} else {
				res = RES_ERROR;
			}
		} else {
			if (SD_WriteMultipleBlock(buff, sector, count) == 0) {
				res = RES_OK;
			} else {
				res = RES_ERROR;
			}
		}
	#endif
		log_d("disk_write DEV_MMC\n");
		return res;

	case DEV_USB :
		// translate the arguments here

		// result = USB_disk_write(buff, sector, count);

		// translate the reslut code here
		log_d("disk_write DEV_USB\n");
		return res;

	case DEV_NOR:
	{
		#if TCFG_DRV_SPI_NORFLASH_SUPPORT
		uint8_t i;
		BYTE *buf = buff;
		log_d("disk_write DEV_NOR\n");
		for (i=0; i<count; i++)
		{
			// 写之前必须先擦除写入扇区：擦除512字节 = 2页
			NorFlash_Erase(NORFLASH_ERASE_PAGE, sector * NORFLASH_FATFS_SECTOR_SIZE);		// 擦除页
			NorFlash_Erase(NORFLASH_ERASE_PAGE, sector * NORFLASH_FATFS_SECTOR_SIZE + NORFLASH_PAGE_SIZE);	// 擦除页

			NorFlash_WriteBuffer(buf, sector * NORFLASH_FATFS_SECTOR_SIZE, NORFLASH_FATFS_SECTOR_SIZE);	
			sector += 1; 
		}		
		res = RES_OK;
		#endif
		return res;
	}
		
	}

	return RES_PARERR;
}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res = RES_OK;
	int result;

	switch (pdrv) {
	case DEV_RAM :

		// Process of the command for the RAM drive
		log_d("disk_ioctl DEV_RAM cmd:0x%02x\n", cmd);
		return res;

	case DEV_MMC :
	#if TCFG_DRV_SD_CARD_SPI_SUPPORT
		// Process of the command for the MMC/SD card
		log_d("disk_ioctl DEV_MMC cmd:%d\n", cmd);
		if (CTRL_SYNC == cmd) {
			log_d("CTRL_SYNC\n");
			
		} else if (GET_SECTOR_COUNT == cmd) {
			log_d("GET_SECTOR_COUNT\n");
			// *(DWORD *)buff = 1536;

		} else if (GET_SECTOR_SIZE == cmd) {
			log_d("GET_SECTOR_SIZE\n");
			*(WORD *)buff = 512;

		} else if (GET_BLOCK_SIZE == cmd) { 
			log_d("GET_BLOCK_SIZE\n");
			*(WORD *)buff = 1 ;   //每次擦除一个扇区

		} else if (CTRL_TRIM == cmd) {
			log_d("CTRL_TRIM\n");
		}
	#endif
		return res;

	case DEV_USB :

		// Process of the command the USB drive
		log_d("disk_ioctl DEV_USB cmd:%d\n", cmd);
		return res;


	case DEV_NOR:
		#if TCFG_DRV_SPI_NORFLASH_SUPPORT
		log_d("disk_ioctl DEV_NOR cmd:%d\n", cmd);
		if (CTRL_SYNC == cmd) {
			log_d("CTRL_SYNC\n");
			res = RES_OK;
		} else if (GET_SECTOR_SIZE == cmd) {
			log_d("GET_SECTOR_SIZE\n");
			// 这个是文件系统每次操作的扇区大小，不一定非要和Norflash的扇区大小一致，但最小值一般为512字节。
			// 一般单片机RAM资源有限文件系统不能是以实际扇区或块大小来操作
			// 这里定义文件系统扇区大小为2个页，需要Norflash支持页擦除指令
			*(DWORD *)buff = NORFLASH_FATFS_SECTOR_SIZE; // NorFlash 最小读写扇区大小
			res = RES_OK;
		} else if (GET_SECTOR_COUNT == cmd) {
			log_d("GET_SECTOR_COUNT\n");
			*(DWORD *)buff = 8192; //NorFlash扇区个数 = 总容量/文件系统扇区大小  4MB=(4194304/512)=8192个扇区; 
			res = RES_OK;
		} else if (GET_BLOCK_SIZE == cmd) { 
			log_d("GET_BLOCK_SIZE\n");
			*(DWORD *)buff = 1;   //每次擦除的扇区个数，1
			res = RES_OK;
		} else if (CTRL_TRIM == cmd) {
			log_d("CTRL_TRIM\n");
			res = RES_OK;
		}
		#endif
		return res;
	}


	return RES_PARERR;
}


/**
 * @brief	获取日期
*/
DWORD get_fattime (void)
{
/*
	Return Value
	Currnet local time shall be returned as bit-fields packed into a DWORD value. The bit fields are as follows:

	bit31:25
		Year origin from the 1980 (0..127, e.g. 37 for 2017)
	bit24:21
		Month (1..12)
	bit20:16
		Day of the month (1..31)
	bit15:11
		Hour (0..23)
	bit10:5
		Minute (0..59)
	bit4:0
		Second / 2 (0..29, e.g. 25 for 50)	
*/
    return ((DWORD)(2010 - 1980) << 25) | ((DWORD)1 << 16) | ((DWORD)0 << 11) | ((DWORD)0 << 5) | ((DWORD)0 >> 1);
}

#if 0
DWORD get_fattime (void)
{
    time_t t;
    struct tm *stm;

    t = time(0);
    stm = localtime(&t);

    return (DWORD)(stm->tm_year - 80) << 25 |
           (DWORD)(stm->tm_mon + 1) << 21 |
           (DWORD)stm->tm_mday << 16 |
           (DWORD)stm->tm_hour << 11 |
           (DWORD)stm->tm_min << 5 |
           (DWORD)stm->tm_sec >> 1;
}
#endif



#if 0  // SD卡文件系统测试		
	// 挂载文件系统 DEV_RAM
	res = f_mount(&fatFS, "0:", 1);	// 最后一个参数0：延时挂载，1：立即挂载
	log_d("f_mount res:%d\n", res);

	// 挂载文件系统 DEV_MMC 
	res = f_mount(&fatFS, "1:", 1);
	log_d("f_mount res:%d\n", res);

	// 挂载文件系统 DEV_USB
	res = f_mount(&fatFS, "2:", 1);
	log_d("f_mount res:%d\n", res);


	// 挂载文件系统 DEV_MMC  尝试创建文件系统  打开文件  写入文件 读取文件
	FATFS fatFS;
	BYTE work[FF_MAX_SS];
	FRESULT res;
	FIL fp;
	res = f_mount(&fatFS, "1:", 1);
	log_d("f_mount res:%d\n", res);
	if (res == FR_NO_FILESYSTEM) {
		log_d("f_mkfs res:%d\n", res);
		res = f_mkfs("1:", 0, work, sizeof(work));
		res = f_mount(NULL, "1:", 1);	// 取消文件系统
		res = f_mount(&fatFS, "1:", 1);	// 挂载文件系统
		log_d("f_mount 222 res:%d\n", res);
	}
	res = f_open(&fp , "1:abcd.txt" , FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_READ |FA_WRITE );
	printf("res = %d\r\n",res);
	if (FR_OK == res) {
		unsigned int wb;
		if (f_write(&fp, "hello world", sizeof("hello world"), &wb) == FR_OK) {
			log_d("write ok:%d\n", wb);
		} else {
			log_d("write err\n");
		}
	}
	f_sync(&fp);
	f_close(&fp);


	// 读测试
	unsigned int rb;
	unsigned char buf[64];
	res = f_open(&fp , "1:A1.txt" , FA_OPEN_ALWAYS|FA_READ |FA_WRITE );
	if (f_read(&fp, (char*)buf, 64, &rb) == FR_OK) {
		log_d("read buf %d:%s\n", rb, buf);
	} else {
		log_d("read buf err\n");
	}
	f_close(&fp);


	SD_GetCardInfo(); // 获取卡CSD,CID信息

	SD_GetStatus(0);
#endif

#if 0 // Norflash 文件系统测试

static FATFS nor_fatfs; // 必须是全局变量
static BYTE nor_work[FF_MAX_SS]; // 必须是全局变量

FRESULT res;
FIL nor_fp;

// 挂在文件系统
res = f_mount(&nor_fatfs, "3:", 1);	// 挂载SD卡，0=DEV_RAM, 1=DEV_MMC, 2=DEV_USB, 3=DEV_NOR
log_d("norflash f_mount res:%d\n", res);
if (res == FR_NO_FILESYSTEM) {
	// 无文件系统，尝试创建文件系统
	res = f_mkfs("3:", 0, nor_work, sizeof(nor_work));
	if (FR_OK == res) {
		/* 格式化后，先取消挂载 */
		f_mount(NULL, "3:", 1);	// 取消文件系统
		res = f_mount(&nor_fatfs, "3:", 1);	// 挂载文件系统
		log_d("norflash f_mount  222 res:%d\n", res);						
	}
}

if (FR_OK == res) {
	// 挂载成功
}


// 写文件
#define D_TEST_STR "The realm of fast artificial neural networks (ANNs) stands as a pinnacle of modern computational intelligence. These networks mimic the human brain’s ability to learn from vast amounts of data, making them invaluable in processing complex patterns quickly. The core of their speed lies in their unique architecture, which allows for parallel processing, akin to how neurons in the human brain operate simultaneously. At the heart of these networks are activation functions, which determine the output of neural computations. These functions are crucial as they introduce non-linearity into the system, enabling the network to learn and make sense of complicated data inputs. By effectively handling these computations, fast ANNs can perform tasks ranging from image recognition to language processing at remarkable speeds."
res = f_open(&nor_fp , "3:abcd.txt" , FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_READ |FA_WRITE );
printf("write f_open res = %d\r\n",res);
if (FR_OK == res) {
	unsigned int wb;
	if (f_write(&nor_fp, D_TEST_STR, strlen(D_TEST_STR), &wb) == FR_OK) {
		log_d("write ok:%d\n", wb);
	} else {
		log_d("write err\n");
	}
}
f_sync(&nor_fp);
f_close(&nor_fp);

// 读文件
unsigned int rb;
unsigned char buf[1024]={0};
res = f_open(&nor_fp , "3:abcd.txt" , FA_OPEN_ALWAYS|FA_READ |FA_WRITE );
printf("rd res f_open = %d\r\n",res);
if (f_read(&nor_fp, (char*)buf, sizeof(buf), &rb) == FR_OK) {
	log_d("read buf %d:%s\n", rb, buf);
} else {
	log_d("read buf err\n");
}
f_close(&nor_fp);		

#endif

#endif //TCFG_LIB_FATFS_SUPPORT